// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.linqingying.gitcode.pullrequest.ui.emoji

import com.intellij.collaboration.async.launchNow
import com.intellij.collaboration.async.mapState
import com.intellij.collaboration.ui.icon.IconsProvider
import com.intellij.platform.util.coroutines.childScope
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import com.linqingying.gitcode.api.data.GCReaction
import com.linqingying.gitcode.api.data.GCReactionContent
import com.linqingying.gitcode.api.data.GCUser
import com.linqingying.gitcode.pullrequest.data.GCReactionsService

interface GCReactionsViewModel {
  val reactionIconsProvider: IconsProvider<GCReactionContent>
  val reactionsWithInfo: StateFlow<Map<GCReactionContent, ReactionInfo>>

  fun toggle(reactionContent: GCReactionContent)
}

internal class GCReactionViewModelImpl(
  parentCs: CoroutineScope,
  private val reactableId: String,
  reactionsFlow: StateFlow<List<GCReaction>>,
  private val currentUser: GCUser,
  private val reactionsService: GCReactionsService,
  override val reactionIconsProvider: IconsProvider<GCReactionContent>
) : GCReactionsViewModel {
  private val cs = parentCs.childScope(CoroutineName("GitCode Reactions View Model"))

  private val reactionsState = MutableStateFlow(reactionsFlow.value)

  init {
    cs.launchNow {
      reactionsFlow.collect(reactionsState)
    }
  }

  override val reactionsWithInfo: StateFlow<Map<GCReactionContent, ReactionInfo>> = reactionsState.mapState(cs) { data ->
    val reactionToUsers = data.groupBy({ it.content }, { it.user })
    reactionToUsers.mapValues { (_, users) ->
      ReactionInfo(users, users.map(GCUser::id).contains(currentUser.id))
    }
  }

  override fun toggle(reactionContent: GCReactionContent) {
    cs.launch {
      val isReacted = reactionsWithInfo.value[reactionContent]?.isReactedByCurrentUser ?: false
      if (isReacted) {
        val reaction = reactionsService.removeReaction(reactableId, reactionContent)
        reactionsState.update { it - reaction }
      }
      else {
        val reaction = reactionsService.addReaction(reactableId, reactionContent)
        reactionsState.update { it + reaction }
      }
    }
  }
}

data class ReactionInfo(
  val users: List<GCUser>,
  val isReactedByCurrentUser: Boolean
)
